﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PowersourceUIToolkit;

namespace UCL.Powersource
{
    public abstract class ViewModelBase : PropertyChangedBase, IViewModel
    {

        protected ILog Log { get; private set; }
        protected IUIManager UIManager { get; private set; }

        protected ViewModelBase()
        {
            Log = LogManager.GetLog(this.GetType());
            UIManager = IoC.Get<IUIManager>();
        }

        protected abstract bool OnInitializing();
        protected abstract bool OnActivating();
        protected abstract bool OnDeactivating();
        protected abstract void OnDisposing();
        

        public event EventHandler Initialized;
        public event EventHandler Activated;
        public event EventHandler Deactivated;
        public event EventHandler Disposed;

        private bool _IsInitialized;

        public bool IsInitialized
        {
            get { return _IsInitialized; }
            private set
            {
                if (_IsInitialized == value) return;
                else
                {
                    Debug.Assert(value, "IsInitialized should never be set to false!");
                    _IsInitialized = value;
                    NotifyOfPropertyChange(() => IsInitialized);
                    NotifyOfPropertyChange(() => IsLoaded);
                    RaiseEvent(Initialized);
                }
            }
        }
        private bool _IsActivated;
        public bool IsActivated
        {
            get { return _IsActivated; }
            private set
            {
                if (_IsActivated == value) return;
                else
                {
                    _IsActivated = value;
                    NotifyOfPropertyChange(() => IsActivated);
                    if (_IsActivated)
                    {
                        RaiseEvent(Activated);
                    }
                    else
                    {
                        RaiseEvent(Deactivated);
                    }
                }
            }
        }

        protected void RaiseEvent(EventHandler StdEvent,object sender=null)
            
        {
            if (sender == null) sender = this;
            if (StdEvent != null)
            {
                StdEvent(this, EventArgs.Empty);
            }
        }

        private bool _IsDisposed;
        public bool IsDisposed
        {
            get { return _IsDisposed; }
            private set
            {
                if (_IsDisposed == value) return;
                else
                {
                    Debug.Assert(value, "IsDisposed should never be set to false. It has false as an initial value and once set to true itForFE cannot be set back to false!");
                    _IsDisposed = value;
                    NotifyOfPropertyChange(() => IsDisposed);
                    NotifyOfPropertyChange(() => IsLoaded);
                }
            }
        }

        public bool IsLoaded { get { return IsInitialized && !IsDisposed; } }

        public void Initialize()
        {
            if (IsInitialized) return;
            if (!OnInitializing()) throw new InvalidOperationException(string.Format("ViewModel {0} cannot be initialized", this.GetType().FullName));
            else { IsInitialized = true; IsActivated = false; NotifyOfPropertyChange(() => IsInitialized); }
        }
        public void Activate()
        {
            if (!IsInitialized) Initialize();
            if (IsActivated) return;
            if (!TryActivate())
                Log.Warn("ViewModel {0} cannot be activated", this.GetType().FullName);
            else
            {
                Log.Trace("ViewModel {0} [{1}]  activated", this.GetType().FullName, this.GetHashCode());
                IsActivated = true;
            }
        }

        public bool TryActivate()
        {
            return OnActivating();
        }

        public bool TryDeactivate()
        {
            return OnDeactivating();
        }

        public void Deactivate()
        {
            if (!IsActivated) return;
            if (!TryDeactivate())
                Log.Warn("ViewModel {0} cannot be deactivated", this.GetType().FullName);
            else { IsActivated = false; }
        }


        protected virtual void Dispose(bool disposing)
        {
            
            if (Log != null && !disposing) { Log.Warn("ViewModel {0} disposed incorrectly", this.GetType().FullName); }

            if (disposing && !IsDisposed)
            {
                if (IsActivated) Deactivate();
                OnDisposing();
                if (Log!=null) Log.Trace("{0} disposed, supressing Finalize", this.GetType().FullName);
                IsDisposed = true;

                GC.SuppressFinalize(this);
                if (Disposed != null) Disposed(this, EventArgs.Empty);
            }
        }

        ~ViewModelBase()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
        }

    }
}
